﻿package org.flixel.system
{
    import org.flixel.*;

    public class FlxQuadTree extends FlxRect
    {
        protected var _canSubdivide:Boolean;
        protected var _headA:FlxList;
        protected var _tailA:FlxList;
        protected var _headB:FlxList;
        protected var _tailB:FlxList;
        protected var _northWestTree:FlxQuadTree;
        protected var _northEastTree:FlxQuadTree;
        protected var _southEastTree:FlxQuadTree;
        protected var _southWestTree:FlxQuadTree;
        protected var _leftEdge:Number;
        protected var _rightEdge:Number;
        protected var _topEdge:Number;
        protected var _bottomEdge:Number;
        protected var _halfWidth:Number;
        protected var _halfHeight:Number;
        protected var _midpointX:Number;
        protected var _midpointY:Number;
        public static const A_LIST:uint = 0;
        public static const B_LIST:uint = 1;
        public static var divisions:uint;
        static var _min:uint;
        static var _object:FlxObject;
        static var _objectLeftEdge:Number;
        static var _objectTopEdge:Number;
        static var _objectRightEdge:Number;
        static var _objectBottomEdge:Number;
        static var _list:uint;
        static var _useBothLists:Boolean;
        static var _processingCallback:Function;
        static var _notifyCallback:Function;
        static var _iterator:FlxList;
        static var _objectHullX:Number;
        static var _objectHullY:Number;
        static var _objectHullWidth:Number;
        static var _objectHullHeight:Number;
        static var _checkObjectHullX:Number;
        static var _checkObjectHullY:Number;
        static var _checkObjectHullWidth:Number;
        static var _checkObjectHullHeight:Number;

        public function FlxQuadTree(param1:Number, param2:Number, param3:Number, param4:Number, param5:FlxQuadTree = null)
        {
            var _loc_6:FlxList = null;
            var _loc_7:FlxList = null;
            super(param1, param2, param3, param4);
            var _loc_8:* = new FlxList();
            this._tailA = new FlxList();
            this._headA = _loc_8;
            var _loc_8:* = new FlxList();
            this._tailB = new FlxList();
            this._headB = _loc_8;
            if (param5 != null)
            {
                if (param5._headA.object != null)
                {
                    _loc_6 = param5._headA;
                    while (_loc_6 != null)
                    {
                        
                        if (this._tailA.object != null)
                        {
                            _loc_7 = this._tailA;
                            this._tailA = new FlxList();
                            _loc_7.next = this._tailA;
                        }
                        this._tailA.object = _loc_6.object;
                        _loc_6 = _loc_6.next;
                    }
                }
                if (param5._headB.object != null)
                {
                    _loc_6 = param5._headB;
                    while (_loc_6 != null)
                    {
                        
                        if (this._tailB.object != null)
                        {
                            _loc_7 = this._tailB;
                            this._tailB = new FlxList();
                            _loc_7.next = this._tailB;
                        }
                        this._tailB.object = _loc_6.object;
                        _loc_6 = _loc_6.next;
                    }
                }
            }
            else
            {
                _min = (width + height) / (2 * divisions);
            }
            this._canSubdivide = width > _min || height > _min;
            this._northWestTree = null;
            this._northEastTree = null;
            this._southEastTree = null;
            this._southWestTree = null;
            this._leftEdge = x;
            this._rightEdge = x + width;
            this._halfWidth = width / 2;
            this._midpointX = this._leftEdge + this._halfWidth;
            this._topEdge = y;
            this._bottomEdge = y + height;
            this._halfHeight = height / 2;
            this._midpointY = this._topEdge + this._halfHeight;
            return;
        }// end function

        public function destroy() : void
        {
            this._headA.destroy();
            this._headA = null;
            this._tailA.destroy();
            this._tailA = null;
            this._headB.destroy();
            this._headB = null;
            this._tailB.destroy();
            this._tailB = null;
            if (this._northWestTree != null)
            {
                this._northWestTree.destroy();
            }
            this._northWestTree = null;
            if (this._northEastTree != null)
            {
                this._northEastTree.destroy();
            }
            this._northEastTree = null;
            if (this._southEastTree != null)
            {
                this._southEastTree.destroy();
            }
            this._southEastTree = null;
            if (this._southWestTree != null)
            {
                this._southWestTree.destroy();
            }
            this._southWestTree = null;
            _object = null;
            _processingCallback = null;
            _notifyCallback = null;
            return;
        }// end function

        public function load(param1:FlxBasic, param2:FlxBasic = null, param3:Function = null, param4:Function = null) : void
        {
            this.add(param1, A_LIST);
            if (param2 != null)
            {
                this.add(param2, B_LIST);
                _useBothLists = true;
            }
            else
            {
                _useBothLists = false;
            }
            _notifyCallback = param3;
            _processingCallback = param4;
            return;
        }// end function

        public function add(param1:FlxBasic, param2:uint) : void
        {
            var _loc_3:uint = 0;
            var _loc_4:FlxBasic = null;
            var _loc_5:Array = null;
            var _loc_6:uint = 0;
            _list = param2;
            if (param1 is FlxGroup)
            {
                _loc_3 = 0;
                _loc_5 = (param1 as FlxGroup).members;
                _loc_6 = (param1 as FlxGroup).length;
                while (_loc_3 < _loc_6)
                {
                    
                    _loc_4 = _loc_5[_loc_3++] as FlxBasic;
                    if (_loc_4 != null && _loc_4.exists)
                    {
                        if (_loc_4 is FlxGroup)
                        {
                            this.add(_loc_4, param2);
                            continue;
                        }
                        if (_loc_4 is FlxObject)
                        {
                            _object = _loc_4 as FlxObject;
                            if (_object.exists && _object.allowCollisions)
                            {
                                _objectLeftEdge = _object.x;
                                _objectTopEdge = _object.y;
                                _objectRightEdge = _object.x + _object.width;
                                _objectBottomEdge = _object.y + _object.height;
                                this.addObject();
                            }
                        }
                    }
                }
            }
            else
            {
                _object = param1 as FlxObject;
                if (_object.exists && _object.allowCollisions)
                {
                    _objectLeftEdge = _object.x;
                    _objectTopEdge = _object.y;
                    _objectRightEdge = _object.x + _object.width;
                    _objectBottomEdge = _object.y + _object.height;
                    this.addObject();
                }
            }
            return;
        }// end function

        protected function addObject() : void
        {
            if (!this._canSubdivide || this._leftEdge >= _objectLeftEdge && this._rightEdge <= _objectRightEdge && this._topEdge >= _objectTopEdge && this._bottomEdge <= _objectBottomEdge)
            {
                this.addToList();
                return;
            }
            if (_objectLeftEdge > this._leftEdge && _objectRightEdge < this._midpointX)
            {
                if (_objectTopEdge > this._topEdge && _objectBottomEdge < this._midpointY)
                {
                    if (this._northWestTree == null)
                    {
                        this._northWestTree = new FlxQuadTree(this._leftEdge, this._topEdge, this._halfWidth, this._halfHeight, this);
                    }
                    this._northWestTree.addObject();
                    return;
                }
                if (_objectTopEdge > this._midpointY && _objectBottomEdge < this._bottomEdge)
                {
                    if (this._southWestTree == null)
                    {
                        this._southWestTree = new FlxQuadTree(this._leftEdge, this._midpointY, this._halfWidth, this._halfHeight, this);
                    }
                    this._southWestTree.addObject();
                    return;
                }
            }
            if (_objectLeftEdge > this._midpointX && _objectRightEdge < this._rightEdge)
            {
                if (_objectTopEdge > this._topEdge && _objectBottomEdge < this._midpointY)
                {
                    if (this._northEastTree == null)
                    {
                        this._northEastTree = new FlxQuadTree(this._midpointX, this._topEdge, this._halfWidth, this._halfHeight, this);
                    }
                    this._northEastTree.addObject();
                    return;
                }
                if (_objectTopEdge > this._midpointY && _objectBottomEdge < this._bottomEdge)
                {
                    if (this._southEastTree == null)
                    {
                        this._southEastTree = new FlxQuadTree(this._midpointX, this._midpointY, this._halfWidth, this._halfHeight, this);
                    }
                    this._southEastTree.addObject();
                    return;
                }
            }
            if (_objectRightEdge > this._leftEdge && _objectLeftEdge < this._midpointX && _objectBottomEdge > this._topEdge && _objectTopEdge < this._midpointY)
            {
                if (this._northWestTree == null)
                {
                    this._northWestTree = new FlxQuadTree(this._leftEdge, this._topEdge, this._halfWidth, this._halfHeight, this);
                }
                this._northWestTree.addObject();
            }
            if (_objectRightEdge > this._midpointX && _objectLeftEdge < this._rightEdge && _objectBottomEdge > this._topEdge && _objectTopEdge < this._midpointY)
            {
                if (this._northEastTree == null)
                {
                    this._northEastTree = new FlxQuadTree(this._midpointX, this._topEdge, this._halfWidth, this._halfHeight, this);
                }
                this._northEastTree.addObject();
            }
            if (_objectRightEdge > this._midpointX && _objectLeftEdge < this._rightEdge && _objectBottomEdge > this._midpointY && _objectTopEdge < this._bottomEdge)
            {
                if (this._southEastTree == null)
                {
                    this._southEastTree = new FlxQuadTree(this._midpointX, this._midpointY, this._halfWidth, this._halfHeight, this);
                }
                this._southEastTree.addObject();
            }
            if (_objectRightEdge > this._leftEdge && _objectLeftEdge < this._midpointX && _objectBottomEdge > this._midpointY && _objectTopEdge < this._bottomEdge)
            {
                if (this._southWestTree == null)
                {
                    this._southWestTree = new FlxQuadTree(this._leftEdge, this._midpointY, this._halfWidth, this._halfHeight, this);
                }
                this._southWestTree.addObject();
            }
            return;
        }// end function

        protected function addToList() : void
        {
            var _loc_1:FlxList = null;
            if (_list == A_LIST)
            {
                if (this._tailA.object != null)
                {
                    _loc_1 = this._tailA;
                    this._tailA = new FlxList();
                    _loc_1.next = this._tailA;
                }
                this._tailA.object = _object;
            }
            else
            {
                if (this._tailB.object != null)
                {
                    _loc_1 = this._tailB;
                    this._tailB = new FlxList();
                    _loc_1.next = this._tailB;
                }
                this._tailB.object = _object;
            }
            if (!this._canSubdivide)
            {
                return;
            }
            if (this._northWestTree != null)
            {
                this._northWestTree.addToList();
            }
            if (this._northEastTree != null)
            {
                this._northEastTree.addToList();
            }
            if (this._southEastTree != null)
            {
                this._southEastTree.addToList();
            }
            if (this._southWestTree != null)
            {
                this._southWestTree.addToList();
            }
            return;
        }// end function

        public function execute() : Boolean
        {
            var _loc_2:FlxList = null;
            var _loc_1:Boolean = false;
            if (this._headA.object != null)
            {
                _loc_2 = this._headA;
                while (_loc_2 != null)
                {
                    
                    _object = _loc_2.object;
                    if (_useBothLists)
                    {
                        _iterator = this._headB;
                    }
                    else
                    {
                        _iterator = _loc_2.next;
                    }
                    if (_object.exists && _object.allowCollisions > 0 && _iterator != null && _iterator.object != null && _iterator.object.exists && this.overlapNode())
                    {
                        _loc_1 = true;
                    }
                    _loc_2 = _loc_2.next;
                }
            }
            if (this._northWestTree != null && this._northWestTree.execute())
            {
                _loc_1 = true;
            }
            if (this._northEastTree != null && this._northEastTree.execute())
            {
                _loc_1 = true;
            }
            if (this._southEastTree != null && this._southEastTree.execute())
            {
                _loc_1 = true;
            }
            if (this._southWestTree != null && this._southWestTree.execute())
            {
                _loc_1 = true;
            }
            return _loc_1;
        }// end function

        protected function overlapNode() : Boolean
        {
            var _loc_2:FlxObject = null;
            var _loc_1:Boolean = false;
            while (_iterator != null)
            {
                
                if (!(!_object.exists || _object.allowCollisions <= 0))
                {
                    _loc_2 = _iterator.object;
                    if (_object === _loc_2 || !_loc_2.exists || _loc_2.allowCollisions <= 0)
                    {
                        _iterator = _iterator.next;
                        continue;
                    }
                    _objectHullX = _object.x < _object.last.x ? (_object.x) : (_object.last.x);
                    _objectHullY = _object.y < _object.last.y ? (_object.y) : (_object.last.y);
                    _objectHullWidth = _object.x - _object.last.x;
                    _objectHullWidth = _object.width + (_objectHullWidth > 0 ? (_objectHullWidth) : (-_objectHullWidth));
                    _objectHullHeight = _object.y - _object.last.y;
                    _objectHullHeight = _object.height + (_objectHullHeight > 0 ? (_objectHullHeight) : (-_objectHullHeight));
                    _checkObjectHullX = _loc_2.x < _loc_2.last.x ? (_loc_2.x) : (_loc_2.last.x);
                    _checkObjectHullY = _loc_2.y < _loc_2.last.y ? (_loc_2.y) : (_loc_2.last.y);
                    _checkObjectHullWidth = _loc_2.x - _loc_2.last.x;
                    _checkObjectHullWidth = _loc_2.width + (_checkObjectHullWidth > 0 ? (_checkObjectHullWidth) : (-_checkObjectHullWidth));
                    _checkObjectHullHeight = _loc_2.y - _loc_2.last.y;
                    _checkObjectHullHeight = _loc_2.height + (_checkObjectHullHeight > 0 ? (_checkObjectHullHeight) : (-_checkObjectHullHeight));
                    if (_objectHullX + _objectHullWidth > _checkObjectHullX && _objectHullX < _checkObjectHullX + _checkObjectHullWidth && _objectHullY + _objectHullHeight > _checkObjectHullY && _objectHullY < _checkObjectHullY + _checkObjectHullHeight)
                    {
                        if (_processingCallback == null || _processingCallback(_object, _loc_2))
                        {
                            _loc_1 = true;
                        }
                        if (_loc_1 && _notifyCallback != null)
                        {
                            _notifyCallback(_object, _loc_2);
                        }
                    }
                    _iterator = _iterator.next;
                }
            }
            return _loc_1;
        }// end function

    }
}
